<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>

  <body>
    <script>
      var baiqi = {
        name: "白起",
        nickname: undefined,
        // baiqi.skill()
        skill: function () {
          console.log(this.name, "施放嘲讽");
        },
        soldiers: [
          {
            name: "王翦",
            soldiers: [{ name: "王贲" }],
          },
          {
            name: "蒙敖",
            soldiers: [{ name: "蒙恬" }],
          },
        ],
      };

      /* 浅拷贝 */
      function demoShallowCopy() {
        // 直接将对象的地址进行拷贝
        var baiqiCopy = baiqi;

        // 浅拷贝的结果：修改任何一个副本 都会影响其它的副本
        baiqiCopy.name = "黑崎";
        console.log(baiqi);
        console.log(baiqiCopy);
      }

      /* 
      深拷贝之JSON：先将对象转为JSON再转换回对象 新对象与老对象保持一致 但地址全新 
      用JSON方式拷贝出来的副本，会丢失值为function以及undefined的信息
      */
      function demoDeepCopy1() {
        function deepCopyByJson(obj) {
          var jsonStr = JSON.stringify(obj);
          var newObj = JSON.parse(jsonStr);
          return newObj;
        }

        var baiqiCopy = deepCopyByJson(baiqi);

        /* 修改副本不影响本体 */
        baiqiCopy.name = "白睡";
        baiqiCopy.soldiers[0].name = "杀马特";
        console.log(baiqiCopy);
        console.log(baiqi);
      }

      /* 深拷贝 */
      function deepCopyByRecursion(data) {
        /* 如果obj直接是基本数据类型 直接返回一个值拷贝 */
        if (typeof data !== "object" && typeof data !== "function") {
          return data;
        }

        /* 
        如果obj是函数 直接返回函数地址（本质上是浅拷贝）   
        函数的拷贝并不担心相互影响：要修改函数=重新赋值=值变成新函数地址=与老的函数地址脱钩=依然并不影响
        */
        if (typeof data === "function") {
          return data;
        }

        /* 深拷贝数组 */
        if (Array.isArray(data)) {
          var arrCopy = [];
          // 对所有元素进行拷贝
          data.forEach(function (item, index) {
            // 直接将当前元素深拷贝一份 丢于副本数组中的相同序号下
            arrCopy[index] = deepCopyByRecursion(item);
          });
          return arrCopy;
        }

        /* obj是对象 */
        var objCopy = {};
        for (var key in data) {
          var value = data[key];
          objCopy[key] = deepCopyByRecursion(value);
        }
        return objCopy;
      }

      /* 拷贝基本数据类型 */
      function testBasic() {
        var str = "李牧";
        var strCopy = deepCopyByRecursion(str);
        strCopy += "放羊";
        console.log(str, strCopy);
      }

      function testFunction() {
        function fn() {
          console.log("hello");
        }
        var fnCopy = deepCopyByRecursion(fn);
        fnCopy = function () {
          console.log("goodbye");
        };
        fn();
        fnCopy();
      }
      //   testFunction();

      function testArray() {
        var arr = [
          {
            name: "王翦",
            soldiers: [{ name: "王贲" }],
            skill: function () {
              console.log("要不要办一张会员卡");
            },
          },
          {
            name: "蒙敖",
            soldiers: [{ name: "蒙恬" }],
          },
          "处理剂",
          "魏冉",
        ];

        var arrCopy = deepCopyByRecursion(arr);
        arrCopy[3] = "美髯公";
        arrCopy[0].name = "洗剪吹";
        arrCopy[0].skill = function () {
          console.log("要不要办一张VIP，只要10万元终身免费洗剪吹");
        };

        console.log(arr);
        console.log(arrCopy);
        arr[0].skill();
        arrCopy[0].skill();
      }
      //   testArray();

      function testObj() {
        var baiqiCopy = deepCopyByRecursion(baiqi);

        /* 修改副本不影响本体 */
        baiqiCopy.name = "人屠大魔王";
        baiqiCopy.soldiers[1].name = "蟹钳";
        // 修改方法 重新赋值一个新函数（新地址） 与其它副本的函数地址脱钩 依然互不影响
        baiqiCopy.skill = function () {
          console.log(this.name, "施放活埋");
        };
        console.log(baiqi);
        console.log(baiqiCopy);
        baiqi.skill();
        baiqiCopy.skill();
      }
    </script>
  </body>
</html>
